import { cloneDeep } from 'lodash-es';
import { BATTLE_SKILL_TYPE, NORMAL_ATTACK } from '../../data/battle-skill';
import { BattleSkillCalculator } from '../battle-skill/calculator';
import { BattleSkillFactory } from '../battle-skill/factory';
import { BATTLE_SIDE, type BattleSide, type BattleUnit } from './unit';
import {
  BATTLE_EVENT_TYPE,
  type BattleEvent,
  type BattleEventType,
} from './type';

/**
 * 战斗管理器
 * 控制整个战斗流程、规则和事件系统
 */
export class BattleManager {
  private playerUnits: BattleUnit[] = [];
  private enemyUnits: BattleUnit[] = [];
  private allUnits: BattleUnit[] = [];
  private currentRound: number = 0;
  private currentActionIndex: number = 0;
  private isBattleEnded: boolean = false;
  private eventListeners: Map<string, ((event: BattleEvent) => void)[]> =
    new Map();
  private maxRounds: number;
  private battleLog: BattleEvent[] = [];
  private isDestroyed: boolean = false;

  /**
   * 创建战斗管理器
   * @param maxRounds - 最大回合数限制，默认 50 回合
   */
  constructor(maxRounds: number = 50) {
    this.maxRounds = maxRounds;
  }

  /**
   * 注册战斗事件监听器
   * @param eventType - 要监听的事件类型
   * @param callback - 事件回调函数
   */
  public onEvent(
    eventType: BattleEventType,
    callback: (event: BattleEvent) => void
  ): void {
    this.checkNotDestroyed();
    if (!this.eventListeners.has(eventType)) {
      this.eventListeners.set(eventType, []);
    }
    this.eventListeners.get(eventType)!.push(callback);
  }

  /**
   * 移除事件监听器
   * @param eventType - 事件类型
   * @param callback - 要移除的回调函数
   */
  public offEvent(
    eventType: BattleEventType,
    callback: (event: BattleEvent) => void
  ): void {
    this.checkNotDestroyed();
    const listeners = this.eventListeners.get(eventType);
    if (listeners) {
      const index = listeners.indexOf(callback);
      if (index > -1) {
        listeners.splice(index, 1);
      }
    }
  }

  /**
   * 触发战斗事件
   * @param event - 要触发的事件对象
   */
  private emitEvent(event: BattleEvent): void {
    this.battleLog.push(event);
    if (this.battleLog.length > 50) {
      this.battleLog.shift();
    }
    // 触发日志事件监听器
    const logListeners =
      this.eventListeners.get(BATTLE_EVENT_TYPE.LOG_UPDATE) || [];
    logListeners.forEach((callback) => callback(event));

    // 触发特定类型的事件监听器
    const specificListeners = this.eventListeners.get(event.type) || [];
    specificListeners.forEach((callback) => callback(event));

    // 触发全局监听器（监听所有事件）
    const globalListeners = this.eventListeners.get('*') || [];
    globalListeners.forEach((callback) => callback(event));
  }

  /**
   * 获取完整战斗日志
   * @returns 按时间顺序排列的战斗事件数组
   */
  public getBattleLog(): BattleEvent[] {
    this.checkNotDestroyed();
    return [...this.battleLog];
  }

  /**
   * 获取指定回合的日志
   * @param round - 回合数
   * @returns 该回合发生的事件数组
   */
  getRoundLog(round: number): BattleEvent[] {
    this.checkNotDestroyed();
    return this.battleLog.filter((event) => event.round === round);
  }

  /** 获取最大回合数 */
  public getMaxRounds(): number {
    this.checkNotDestroyed();
    return this.maxRounds;
  }

  /**
   * 设置最大回合数
   * @param maxRounds - 新的最大回合数
   * @throws 如果最大回合数小于1会抛出错误
   */
  setMaxRounds(maxRounds: number): void {
    this.checkNotDestroyed();
    if (maxRounds < 1) throw new Error('最大回合数不能小于1');
    this.maxRounds = maxRounds;
  }

  /**
   * 添加单位到战斗
   * @param unit - 要添加的战斗单位
   */
  public addUnit(unit: BattleUnit): void {
    this.checkNotDestroyed();
    if (unit.side === BATTLE_SIDE.PLAYER) {
      this.playerUnits.push(unit);
    } else {
      this.enemyUnits.push(unit);
    }
    this.allUnits.push(unit);
  }

  /**
   * 从战斗中移除单位
   * @param unitId - 要移除的单位ID
   * @returns 如果成功移除返回true，否则返回false
   */
  public removeUnit(unitId: string): boolean {
    this.checkNotDestroyed();
    const unitIndex = this.allUnits.findIndex((unit) => unit.id === unitId);
    if (unitIndex === -1) return false;

    const unit = this.allUnits[unitIndex] as BattleUnit;
    if (unit.side === BATTLE_SIDE.PLAYER) {
      this.playerUnits = this.playerUnits.filter((u) => u.id !== unitId);
    } else {
      this.enemyUnits = this.enemyUnits.filter((u) => u.id !== unitId);
    }
    this.allUnits.splice(unitIndex, 1);

    return true;
  }

  /** 开始战斗 */
  public startBattle(): void {
    this.checkNotDestroyed();
    if (this.allUnits.length === 0) {
      throw new Error('没有单位参与战斗');
    }

    this.currentRound = 1;
    this.currentActionIndex = 0;
    this.isBattleEnded = false;
    this.battleLog = [];

    this.sortUnitsBySpeed();

    this.emitEvent({
      type: BATTLE_EVENT_TYPE.BATTLE_START,
      round: this.currentRound,
    });
    this.emitEvent({
      type: BATTLE_EVENT_TYPE.ROUND_START,
      round: this.currentRound,
    });
  }

  /** 按速度降序排序所有单位（决定行动顺序） */
  private sortUnitsBySpeed(): void {
    this.allUnits.sort((a, b) => b.speed - a.speed);
  }

  /**
   * 检查战斗是否结束
   * @returns 如果战斗已结束返回true，否则返回false
   */
  private checkBattleEnd(): boolean {
    if (this.isBattleEnded) {
      return true;
    }

    const playerAlive = this.playerUnits.some((unit) => unit.isAlive());
    const enemyAlive = this.enemyUnits.some((unit) => unit.isAlive());

    // 检查回合数限制
    if (this.currentRound > this.maxRounds) {
      this.isBattleEnded = true;
      const winner = this.calculateRoundLimitWinner();

      this.emitEvent({
        type: BATTLE_EVENT_TYPE.ROUND_LIMIT_REACHED,
        round: this.currentRound,
        maxRounds: this.maxRounds,
        winner: winner,
      });

      this.emitEvent({
        type: BATTLE_EVENT_TYPE.BATTLE_END,
        winner,
        round: this.currentRound,
      });
      return true;
    }

    // 检查一方是否全灭
    if (!playerAlive || !enemyAlive) {
      this.isBattleEnded = true;
      const winner = playerAlive ? BATTLE_SIDE.PLAYER : BATTLE_SIDE.ENEMY;

      this.emitEvent({
        type: BATTLE_EVENT_TYPE.BATTLE_END,
        winner,
        round: this.currentRound,
      });

      return true;
    }

    return false;
  }

  /**
   * 计算回合限制时的胜利方
   * @returns 胜利方阵营
   */
  private calculateRoundLimitWinner(): BattleSide {
    const enemyHealth = this.enemyUnits.reduce(
      (sum, unit) => sum + unit.currentHealth,
      0
    );

    // 有敌人存活判玩家输
    return enemyHealth === 0 ? BATTLE_SIDE.PLAYER : BATTLE_SIDE.ENEMY;
  }

  /**
   * 获取当前行动的单位
   * @returns 当前应该行动的单位，如果没有存活单位则返回null
   */
  private getCurrentUnit(): BattleUnit | null {
    const aliveUnits = this.allUnits.filter((unit) => unit.isAlive());
    if (aliveUnits.length === 0) return null;

    const currentIndex = this.currentActionIndex % aliveUnits.length;
    return aliveUnits[currentIndex] as BattleUnit;
  }

  /**
   * 执行单个行动（单步模式）
   * @returns 如果成功执行行动返回true，如果战斗已结束返回false
   */
  public executeSingleAction(): boolean {
    this.checkNotDestroyed();
    if (this.checkBattleEnd()) {
      return false;
    }

    const currentUnit = this.getCurrentUnit();
    if (!currentUnit) {
      this.checkBattleEnd();
      return false;
    }

    // 触发单位行动开始事件
    this.emitEvent({
      type: BATTLE_EVENT_TYPE.UNIT_ACTION_START,
      source: currentUnit,
      round: this.currentRound,
    });

    const availableSkills = currentUnit.getSkills();
    /** 随机选择技能 */
    const randomSkill =
      availableSkills[Math.floor(Math.random() * availableSkills.length)];
    const selectedSkill = randomSkill
      ? randomSkill
      : BattleSkillFactory.createBattleSkillByConfig(NORMAL_ATTACK);

    /** 技能使用目标 */
    const targets = BattleSkillCalculator.getSkillTargets(
      selectedSkill,
      currentUnit,
      this.playerUnits,
      this.enemyUnits
    );

    if (targets.length) {
      /** 触发技能使用事件 */
      this.emitEvent({
        type: BATTLE_EVENT_TYPE.SKILL_USE,
        source: currentUnit,
        target: targets,
        skill: selectedSkill,
        round: this.currentRound,
      });

      /** 触发攻击事件 */
      this.emitEvent({
        type: BATTLE_EVENT_TYPE.ATTACK,
        source: currentUnit,
        target: targets,
        skill: selectedSkill,
        round: this.currentRound,
      });

      targets.forEach((target) => {
        let effectValue = 0;
        effectValue = BattleSkillCalculator.calculateSkillValue(
          selectedSkill,
          currentUnit,
          target
        );
        switch (selectedSkill.type) {
          case BATTLE_SKILL_TYPE.HEAL:
            target.heal(effectValue);
            if (effectValue > 0) {
              /** 触发治疗事件 */
              this.emitEvent({
                type: BATTLE_EVENT_TYPE.HEAL,
                source: currentUnit,
                target: [target],
                heal: effectValue,
                skill: selectedSkill,
                round: this.currentRound,
              });
            }
            break;
          case BATTLE_SKILL_TYPE.PHYSICAL:
          case BATTLE_SKILL_TYPE.MAGIC:
            target.takeDamage(effectValue, selectedSkill, currentUnit);
            if (effectValue > 0) {
              /** 触发伤害事件 */
              this.emitEvent({
                type: BATTLE_EVENT_TYPE.DAMAGE,
                source: currentUnit,
                target: [target],
                damage: effectValue,
                skill: selectedSkill,
                round: this.currentRound,
              });
            }
            break;
          default:
            break;
        }
        /** 检查目标是否死亡 */
        if (!target.isAlive()) {
          this.emitEvent({
            type: BATTLE_EVENT_TYPE.UNIT_DEATH,
            source: target,
            round: this.currentRound,
          });
        }
      });
    }

    /** 触发单位行动结束事件 */
    this.emitEvent({
      type: BATTLE_EVENT_TYPE.UNIT_ACTION_END,
      source: currentUnit,
      round: this.currentRound,
    });

    const aliveUnits = this.allUnits.filter((unit) => unit.isAlive());
    this.currentActionIndex += 1;

    const battleEnded = this.checkBattleEnd();

    /** 检查是否进入下一回合 */
    if (!battleEnded && this.currentActionIndex >= aliveUnits.length) {
      /** 触发回合结束事件 */
      this.emitEvent({
        type: BATTLE_EVENT_TYPE.ROUND_END,
        round: this.currentRound,
      });

      this.currentRound += 1;
      this.currentActionIndex = 0;

      if (this.currentRound <= this.maxRounds) {
        this.emitEvent({
          type: BATTLE_EVENT_TYPE.ROUND_START,
          round: this.currentRound,
        });
      } else {
        this.checkBattleEnd();
      }
    }

    return true;
  }

  /** 自动执行整个战斗直到结束 */
  public autoBattle(): void {
    this.checkNotDestroyed();
    let actions = 0;
    const maxActions = this.maxRounds * this.allUnits.length;

    while (!this.isBattleEnded && actions < maxActions) {
      const hasAction = this.executeSingleAction();
      if (!hasAction) break;
      actions += 1;
    }

    // 防止无限循环的安全检查
    if (actions >= maxActions && !this.isBattleEnded) {
      console.warn('战斗达到最大行动次数，强制结束');
      this.isBattleEnded = true;
      const winner = this.calculateRoundLimitWinner();

      this.emitEvent({
        type: BATTLE_EVENT_TYPE.BATTLE_END,
        winner,
        round: this.currentRound,
      });
    }
  }

  /**
   * 获取当前战斗状态
   * @returns 包含当前战斗所有状态信息的对象
   */
  public getBattleState() {
    this.checkNotDestroyed();
    return {
      currentRound: this.currentRound,
      maxRounds: this.maxRounds,
      isBattleEnded: this.isBattleEnded,
      playerUnits: this.playerUnits.map((unit) => unit.getSnapshot()),
      enemyUnits: this.enemyUnits.map((unit) => unit.getSnapshot()),
    };
  }

  /**
   * 获取存活单位数量
   * @returns 包含玩家和敌人存活数量的对象
   */
  public getAliveCounts(): { player: number; enemy: number } {
    this.checkNotDestroyed();
    return {
      player: this.playerUnits.filter((unit) => unit.isAlive()).length,
      enemy: this.enemyUnits.filter((unit) => unit.isAlive()).length,
    };
  }

  /** 获取所有敌人单位 */
  public getEnemyUnits() {
    this.checkNotDestroyed();
    return cloneDeep(this.enemyUnits);
  }

  /**
   * 清场
   */
  public reset() {
    this.checkNotDestroyed();

    this.playerUnits = [];
    this.enemyUnits = [];
    this.allUnits = [];

    this.currentRound = 0;
    this.currentActionIndex = 0;
    this.isBattleEnded = true;
    this.battleLog = [];
  }

  /**
   * 销毁战斗管理器，释放所有资源
   * 调用此方法后，战斗管理器实例将不可再用
   *
   * @example
   * ```typescript
   * const battle = new BattleManager();
   * // ... 使用战斗管理器 ...
   * battle.destroy(); // 使用完毕后清理资源
   * ```
   */
  public destroy(): void {
    if (this.isDestroyed) {
      console.warn('战斗管理器已被销毁，无需重复调用');
      return;
    }

    // 清空所有事件监听器
    this.eventListeners.clear();

    // 清空单位数组（但不需要销毁BattleUnit实例，因为它们可能在其他地方被引用）
    this.playerUnits = [];
    this.enemyUnits = [];
    this.allUnits = [];

    // 清空战斗日志
    this.battleLog = [];

    // 重置战斗状态
    this.currentRound = 0;
    this.currentActionIndex = 0;
    this.isBattleEnded = true;

    // 标记为已销毁
    this.isDestroyed = true;
  }

  /**
   * 安全地执行方法，如果管理器已销毁则抛出错误
   */
  private checkNotDestroyed(): void {
    if (this.isDestroyed) {
      throw new Error('战斗管理器已被销毁，无法执行操作');
    }
  }
}
